using Common.Models;
using Common.Utils;
using FileClient.Models;
using System.IO;
using System.Net;
using System.Net.Http.Headers;
using System.Text.Json;
using NLog;

namespace FileClient.Utils
{

    public class FileDownloadService
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        private readonly HttpClient _httpClient;
        private readonly string _baseUrl;
        private readonly string _downloadDirectory;
        private readonly int _bufferSize = ConfigHelper.BufferSize;
        private readonly int _maxRetries = ConfigHelper.MaxRetries;
        private readonly TimeSpan _retryDelay = ConfigHelper.RetryDelay;


        public event EventHandler<ProgressEventArgs>? DownloadProgressChanged;
        public event EventHandler<string>? DownloadCompleted;
        public event EventHandler<string>? DownloadError;

        public FileDownloadService(string baseUrl, string downloadDirectory)
        {
            _baseUrl = baseUrl.TrimEnd('/');
            _downloadDirectory = downloadDirectory;

            // 创建HttpClientHandler以更好地控制连接
            var handler = new HttpClientHandler
            {
                AutomaticDecompression = System.Net.DecompressionMethods.None, // 禁用自动解压缩
                UseCookies = false, // 禁用Cookie
                AllowAutoRedirect = true, // 允许重定向
                MaxAutomaticRedirections = 3 // 最大重定向次数
            };

            _httpClient = new HttpClient(handler);
            _httpClient.Timeout = ConfigHelper.MaxTimeout;

            // 设置默认请求头
            _httpClient.DefaultRequestHeaders.Clear();
            _httpClient.DefaultRequestHeaders.Add("User-Agent", "FileTransfer-Client/1.0");
            _httpClient.DefaultRequestHeaders.Add("Accept", "*/*");
            _httpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");

            // 确保下载目录存在
            if (!Directory.Exists(_downloadDirectory))
            {
                Directory.CreateDirectory(_downloadDirectory);
            }
        }

        /// <summary>
        /// 测试断点续传功能
        /// </summary>
        public async Task TestRangeRequestAsync(string fileName, long startPosition)
        {
            try
            {
                using var request = new HttpRequestMessage(HttpMethod.Get, $"{_baseUrl}/api/file/download/{Uri.EscapeDataString(fileName)}");
                request.Headers.TryAddWithoutValidation("Range", $"bytes={startPosition}-");

                using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

                Logger.Info("测试Range请求结果:");
                Logger.Info($"状态码: {response.StatusCode}");
                Logger.Info($"Content-Length: {response.Content.Headers.ContentLength}");

                try
                {
                    var contentRange = response.Headers.GetValues("Content-Range").FirstOrDefault();
                    Logger.Info($"Content-Range: {contentRange}");
                }
                catch
                {
                    Logger.Warn("Content-Range: 未设置");
                }

                Logger.Info($"Accept-Ranges: {response.Headers.GetValues("Accept-Ranges").FirstOrDefault()}");
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"测试Range请求失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 测试HTTP连接
        /// </summary>
        public async Task<bool> TestConnectionAsync()
        {
            try
            {
                using var request = new HttpRequestMessage(HttpMethod.Get, $"{_baseUrl}/api/file/list");
                using var response = await _httpClient.SendAsync(request);
                return response.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"连接测试失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 获取文件列表
        /// </summary>
        public async Task<List<FileData>> GetFileListAsync()
        {
            try
            {
                var response = await _httpClient.GetAsync($"{_baseUrl}/api/file/list");
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                var files = JsonSerializer.Deserialize<List<FileData>>(json, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

                return files ?? new List<FileData>();
            }
            catch (Exception ex)
            {
                throw new Exception($"获取文件列表失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取文件信息
        /// </summary>
        public async Task<FileData?> GetFileInfoAsync(string fileName)
        {
            try
            {
                var response = await _httpClient.GetAsync($"{_baseUrl}/api/file/info/{Uri.EscapeDataString(fileName)}");
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                var fileData = JsonSerializer.Deserialize<FileData>(json, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

                return fileData;
            }
            catch (Exception ex)
            {
                throw new Exception($"获取文件信息失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 计算平滑的下载速度
        /// </summary>
        /// <param name="speedHistory">速度历史记录</param>
        /// <param name="instantSpeed">当前瞬时速度</param>
        /// <returns>平滑后的速度</returns>
        private long CalculateSmoothSpeed(Queue<long> speedHistory, long instantSpeed)
        {
            if (speedHistory.Count == 0)
            {
                return instantSpeed;
            }

            // 过滤异常值（如果当前速度与平均值相差太大，则忽略）
            var averageSpeed = speedHistory.Average();
            var threshold = averageSpeed * 0.5; // 允许50%的波动

            if (Math.Abs(instantSpeed - averageSpeed) > threshold)
            {
                // 如果速度变化太大，使用历史平均值
                return (long)averageSpeed;
            }

            // 使用加权平均，最近的速度权重更高
            var speeds = speedHistory.ToList();
            speeds.Add(instantSpeed);

            double weightedSum = 0;
            double weightSum = 0;

            for (int i = 0; i < speeds.Count; i++)
            {
                var weight = i + 1; // 权重递增
                weightedSum += speeds[i] * weight;
                weightSum += weight;
            }

            return (long)(weightedSum / weightSum);
        }

        /// <summary>
        /// 下载文件（支持断点续传）
        /// </summary>
        public async Task DownloadFileAsync(string fileName, CancellationToken cancellationToken = default)
        {
            Logger.Info($"开始下载文件: {fileName}");
            var localFilePath = Path.Combine(_downloadDirectory, fileName);
            var tempFilePath = localFilePath + ".tmp";
            var resumeFilePath = localFilePath + ".resume";

            long resumePosition = 0;
            var startTime = DateTime.Now;
            var lastProgressTime = startTime;
            var lastBytesReceived = 0L;

            // 速度计算相关变量
            var speedHistory = new Queue<long>();
            var maxSpeedHistory = 10; // 保留最近10次的速度记录用于平滑计算

            FileStream? fileStream = null;
            try
            {
                // 检查是否有未完成的下载
                if (File.Exists(resumeFilePath) && File.Exists(tempFilePath))
                {
                    var resumeData = await File.ReadAllTextAsync(resumeFilePath, cancellationToken);
                    if (long.TryParse(resumeData, out var position))
                    {
                        var tempFileInfo = new FileInfo(tempFilePath);
                        // 以临时文件实际大小为准
                        resumePosition = Math.Min(position, tempFileInfo.Length);
                    }
                }
                else
                {
                    // 没有断点文件，正常从头下载
                    resumePosition = 0;
                }

                // 获取文件信息
                var fileData = await GetFileInfoAsync(fileName);
                if (fileData == null)
                {
                    Logger.Warn($"文件不存在: {fileName}");
                    throw new Exception("文件不存在");
                }

                // 检查本地文件是否已完整
                if (File.Exists(localFilePath))
                {
                    var localFileInfo = new FileInfo(localFilePath);
                    if (localFileInfo.Length == fileData.Size)
                    {
                        Logger.Info($"文件已存在且完整: {fileName}");
                        DownloadCompleted?.Invoke(this, localFilePath);
                        return;
                    }
                }

                // 验证断点位置
                if (resumePosition >= fileData.Size)
                {
                    Logger.Info($"断点位置超出文件大小，重置断点: {fileName}");
                    if (File.Exists(resumeFilePath))
                    {
                        File.Delete(resumeFilePath);
                    }
                    if (File.Exists(tempFilePath))
                    {
                        File.Delete(tempFilePath);
                    }
                    // 断点位置超出文件大小，重置断点
                    resumePosition = 0;
                }

                using var request = new HttpRequestMessage(HttpMethod.Get, $"{_baseUrl}/api/file/download/{Uri.EscapeDataString(fileName)}");

                // 设置Range头支持断点续传
                if (resumePosition > 0)
                {
                    try
                    {
                        // 使用TryAddWithoutValidation避免头部验证错误
                        request.Headers.TryAddWithoutValidation("Range", $"bytes={resumePosition}-");
                        Logger.Info($"设置Range请求头: bytes={resumePosition}-");
                    }
                    catch (Exception ex)
                    {
                        Logger.Warn($"设置Range头部失败: {ex.Message}");
                        // 如果设置失败，继续下载但不使用断点续传
                        resumePosition = 0;
                    }
                }

                using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
                response.EnsureSuccessStatusCode();

                // 验证响应头
                var contentLength = response.Content.Headers.ContentLength;
                string? contentRange = null;

                try
                {
                    contentRange = response.Headers.GetValues("Content-Range").FirstOrDefault();
                }
                catch (Exception ex)
                {
                    Logger.Warn($"获取Content-Range头失败: {ex.Message}");
                    // Content-Range头不存在是正常的，特别是在完整下载时
                }

                Logger.Info($"响应状态码: {response.StatusCode}");
                Logger.Info($"Content-Length: {contentLength}");
                Logger.Info($"Content-Range: {contentRange}");

                // 验证响应状态
                if (response.StatusCode == HttpStatusCode.PartialContent)
                {
                    // 部分内容响应，应该包含Content-Range头
                    if (string.IsNullOrEmpty(contentRange))
                    {
                        Logger.Warn("警告: 部分内容响应但缺少Content-Range头");
                    }
                }
                else if (response.StatusCode == HttpStatusCode.OK)
                {
                    // 完整文件响应，Content-Range头是可选的
                    Logger.Info("完整文件响应");
                }

                if (contentLength.HasValue && contentLength.Value <= 0)
                {
                    throw new Exception("服务器返回的内容长度为0");
                }

                using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken);
                fileStream = new FileStream(tempFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, _bufferSize);

                // 如果是从断点续传，设置文件流位置
                if (resumePosition > 0)
                {
                    fileStream.Seek(resumePosition, SeekOrigin.Begin);
                }

                var buffer = new byte[_bufferSize];
                var totalBytesRead = resumePosition;
                var totalBytes = fileData.Size;

                while (true)
                {
                    var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
                    if (bytesRead == 0)
                    {
                        break;
                    }

                    await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
                    totalBytesRead += bytesRead;

                    var currentTime = DateTime.Now;
                    if ((currentTime - lastProgressTime).TotalSeconds >= 1.0)
                    {
                        var timeDiff = (currentTime - lastProgressTime).TotalSeconds;
                        var bytesDiff = totalBytesRead - lastBytesReceived;
                        var instantSpeed = timeDiff > 0 ? (long)(bytesDiff / timeDiff) : 0;

                        speedHistory.Enqueue(instantSpeed);
                        if (speedHistory.Count > maxSpeedHistory)
                            speedHistory.Dequeue();

                        var averageSpeed = CalculateSmoothSpeed(speedHistory, instantSpeed);

                        ProgressEventArgs progress = new ProgressEventArgs
                        {
                            FileName = fileName,
                            BytesReceived = totalBytesRead,
                            TotalBytes = totalBytes,
                            ProgressPercentage = (double)totalBytesRead / totalBytes * 100,
                            DownloadSpeed = averageSpeed,
                            EstimatedTimeRemaining = averageSpeed > 0
                                ? TimeSpan.FromSeconds((totalBytes - totalBytesRead) / averageSpeed)
                                : TimeSpan.Zero
                        };

                        DownloadProgressChanged?.Invoke(this, progress);
                        lastProgressTime = currentTime;
                        lastBytesReceived = totalBytesRead;
                    }
                    // 每次进度事件都保存断点信息
                    await File.WriteAllTextAsync(resumeFilePath, totalBytesRead.ToString(), cancellationToken);
                }

                // 验证下载完整性
                fileStream.Flush();
                fileStream.Close();
                fileStream = null;

                FileInfo downloadedFileInfo = new FileInfo(tempFilePath);
                if (downloadedFileInfo.Length != fileData.Size)
                {
                    throw new Exception($"文件下载不完整: 期望 {fileData.Size} 字节，实际 {downloadedFileInfo.Length} 字节");
                }

                // 下载完成，移动文件到最终位置
                if (File.Exists(localFilePath))
                {
                    File.Delete(localFilePath);
                }
                File.Move(tempFilePath, localFilePath);

                // 下载完成，清理断点和临时文件
                CleanupTempFiles(fileName);

                // 下载完成后再触发一次100%进度
                DownloadProgressChanged?.Invoke(this, new ProgressEventArgs
                {
                    FileName = fileName,
                    BytesReceived = totalBytes,
                    TotalBytes = totalBytes,
                    ProgressPercentage = 100,
                    DownloadSpeed = 0,
                    EstimatedTimeRemaining = TimeSpan.Zero
                });

                DownloadCompleted?.Invoke(this, localFilePath);
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"下载异常: {fileName}");
                // 下载出错时清理断点文件
                if (File.Exists(resumeFilePath))
                {
                    File.Delete(resumeFilePath);
                }
                DownloadError?.Invoke(this, ex.Message);
                throw;
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Dispose();
                    fileStream = null;
                }
            }
        }

        /// <summary>
        /// 取消下载
        /// </summary>
        public void CancelDownload(string fileName)
        {
            Logger.Info($"取消下载: {fileName}");
            // 清理临时文件
            CleanupTempFiles(fileName);
        }

        private void CleanupTempFiles(string fileName)
        {
            var localFilePath = Path.Combine(_downloadDirectory, fileName);
            var tempFilePath = localFilePath + ".tmp";
            var resumeFilePath = localFilePath + ".resume";

            TryDeleteFileWithRetry(tempFilePath);
            TryDeleteFileWithRetry(resumeFilePath);
        }

        /// <summary>
        /// 尝试多次删除文件，避免因文件被占用导致删除失败。
        /// </summary>
        private void TryDeleteFileWithRetry(string filePath, int delayMs = 200)
        {
            for (int i = 0; i < ConfigHelper.MaxRetries; i++)
            {
                try
                {
                    if (File.Exists(filePath))
                    {
                        File.Delete(filePath);
                        if (!File.Exists(filePath))
                        {
                            return;
                        }
                    }
                    else
                    {
                        return;
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, $"删除文件失败: {filePath}");
                }
                Thread.Sleep(delayMs);
            }
        }


        public void Dispose()
        {
            _httpClient?.Dispose();
        }
    }
}